using Behaving;
using NUnit.Framework;

namespace Behaving.Tests
{
    public static class Assertions
    {
        public static void AssertWasStartedAndExecuted(params ExecutionCounter[] executionCounters)
        {
            foreach (var executionCounter in executionCounters)
            {
                TestStart(executionCounter, true);
                TestExecute(executionCounter, true);
                TestStop(executionCounter, false);
                executionCounter.Reset();
            }
        }

        public static void AssertWasNotCalled(params ExecutionCounter[] executionCounters)
        {
            foreach (var executionCounter in executionCounters)
            {
                TestStart(executionCounter, false);
                TestExecute(executionCounter, false);
                TestStop(executionCounter, false);
                executionCounter.Reset();
            }
        }

        public static void AssertWasExecuted(params ExecutionCounter[] executionCounters)
        {
            foreach (var executionCounter in executionCounters)
            {
                TestStart(executionCounter, false);
                TestExecute(executionCounter, true);
                TestStop(executionCounter, false);
                executionCounter.Reset();
            }
        }

        public static void AssertWasStopped(params ExecutionCounter[] executionCounters)
        {
            foreach (var executionCounter in executionCounters)
            {
                TestStart(executionCounter, false);
                TestExecute(executionCounter, false);
                TestStop(executionCounter, true);
                executionCounter.Reset();
            }
        }

        public static void AssertWasExecutedAndStopped(params ExecutionCounter[] executionCounters)
        {
            foreach (var executionCounter in executionCounters)
            {
                TestStart(executionCounter, false);
                TestExecute(executionCounter, true);
                TestStop(executionCounter, true);
                executionCounter.Reset();
            }
        }

        public static void AssertWasStartedExecutedAndStopped(params ExecutionCounter[] executionCounters)
        {
            foreach (var executionCounter in executionCounters)
            {
                TestStart(executionCounter, true);
                TestExecute(executionCounter, true);
                TestStop(executionCounter, true);
                executionCounter.Reset();
            }
        }

        private static void TestExecute(ExecutionCounter executionCounter, bool shouldHaveExecuted)
        {
            if (shouldHaveExecuted && executionCounter.ExecuteCalls != 1)
            {
                Assert.Fail("{0} should have been executed, but ExecuteCalls was {1}", executionCounter.Name, executionCounter.ExecuteCalls);
            }

            if (!shouldHaveExecuted && executionCounter.ExecuteCalls != 0)
            {
                Assert.Fail("{0} should NOT have been executed, but ExecuteCalls was {1}", executionCounter.Name, executionCounter.ExecuteCalls);
            }
        }

        private static void TestStart(ExecutionCounter executionCounter, bool shouldHaveStarted)
        {
            if (shouldHaveStarted && executionCounter.StartCalls != 1)
            {
                Assert.Fail("{0} should have been started, but StartCalls was {1}", executionCounter.Name, executionCounter.StartCalls);
            }

            if (!shouldHaveStarted && executionCounter.StartCalls != 0)
            {
                Assert.Fail("{0} should NOT have been started, but StartCalls was {1}", executionCounter.Name, executionCounter.StartCalls);
            }
        }

        private static void TestStop(ExecutionCounter executionCounter, bool shouldHaveStopped)
        {
            if (shouldHaveStopped && executionCounter.StopCalls != 1)
            {
                Assert.Fail("{0} should have been stopped, but StopCalls was {1}", executionCounter.Name, executionCounter.StopCalls);
            }

            if (!shouldHaveStopped && executionCounter.StopCalls != 0)
            {
                Assert.Fail("{0} should NOT have been stopped, but StopCalls was {1}", executionCounter.Name, executionCounter.StopCalls);
            }
        }
    }
}